﻿using SkiaSharp.Views.Desktop;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using LightCAD.Runtime;
using LightCAD.Core;
using System.Text.Json.Serialization;
using System.Numerics;
using System.IO;
using System.Reflection;
using TestWinform.Properties;
using netDxf.Entities;
using QdArch;

namespace TestWinform
{
    public partial class QdArchShapeEditor : Form
    {
        #region Header

        private List<ICurve2d> shapeCurves;
        private List<ICurve2d> wallCurves;
        private Shape2dProvider provider;
        private string componentType;

        public QdArchShapeEditor()
        {
            InitializeComponent();
            this.Shown += QdArchShapeEditor_Shown;
            this.skGL.PaintSurface += SkGL_PaintSurface;
            this.skGL.MouseClick += SkGL_MouseClick;
            this.skGL.Resize += SkGL_Resize;

            this.txtWallThickness.ValueChanged += TxtWallThickness_ValueChanged;
            this.txtWidth.ValueChanged += TxtWidth_ValueChanged;
            this.txtHeight.ValueChanged += TxtHeight_ValueChanged;
            this.txtBtmOffset.ValueChanged += TxtBtmOffset_ValueChanged;
            this.chkIsLeft.CheckedChanged += ChkIsLeft_CheckedChanged;
            this.chkIsNear.CheckedChanged += ChkIsNear_CheckedChanged;
        }



        #endregion

        #region ResetShape

        private void ChkIsNear_CheckedChanged(object? sender, EventArgs e)
        {
            ResetShape();
        }

        private void ChkIsLeft_CheckedChanged(object? sender, EventArgs e)
        {
            ResetShape();
        }

        private void TxtBtmOffset_ValueChanged(object? sender, EventArgs e)
        {
            ResetShape();
        }

        private void TxtHeight_ValueChanged(object? sender, EventArgs e)
        {
            ResetShape();
        }

        private void TxtWidth_ValueChanged(object? sender, EventArgs e)
        {
            ResetShape();
        }

        private void TxtWallThickness_ValueChanged(object? sender, EventArgs e)
        {
            ResetShape();
        }
        private void lstShape_SelectedIndexChanged(object sender, EventArgs e)
        {
            ResetShape();
        }
        private void ResetShape()
        {
            if (lstShape.SelectedIndex == -1) return;

            var shape = (ComponentShape2d)lstShape.SelectedItem;
            var paramSet = GetParameterSet();
            wallCurves = GetWallShape(paramSet);
            shapeCurves = shape.Generate(paramSet);
            skGL.Invalidate();
        }
        private LcParameterSet GetParameterSet()
        {
            LcParameterSet pset = null;
            if (componentType == "Door")
                pset = new LcParameterSet(QdDoor.ParamsDefinition);
            else if(componentType=="Window")
                pset = new LcParameterSet(QdWindow.ParamsDefinition);

            pset.SetValue("Thickness", (double)txtWallThickness.Value);
            pset.SetValue("Width", (double)txtWidth.Value);
            pset.SetValue("Height", (double)txtHeight.Value);
            pset.SetValue("BottomOffset", (double)txtBtmOffset.Value);
            pset.SetValue("IsLeft", chkIsLeft.Checked);
            pset.SetValue("IsNear", chkIsNear.Checked);
            return pset;
        }

        #endregion

        #region CalFPS
        private DateTime lastTime;
        private int frameIndex;
        public double FPS;
        public string TitleExt;
        protected void CalFPS()
        {
            if (lastTime == DateTime.MinValue)
            {
                lastTime = DateTime.Now;
            }
            frameIndex++;
            var delta = (DateTime.Now - lastTime).TotalSeconds;
            if (delta > 1)
            {
                FPS = Math.Round(frameIndex / delta, 1);
                lastTime = DateTime.Now;
                frameIndex = 0;
            }
            this.Text = FPS.ToString("0.00");
        }
        #endregion

        #region SKRender

        private double scale = 0.3;
        private LightCAD.Core.Vector2 center = new LightCAD.Core.Vector2(0, 0);

        public Matrix3 WcsToScr { get; private set; }
        public Matrix3 ScrToWcs { get; private set; }

        public void ResetCoordMatrix()
        {
            var vp = this.skGL;
            //从屏幕到中心设备坐标系 相当于平移加镜像
            var dcsToScr = Matrix3.Translate(vp.Width / 2, vp.Height / 2) * Matrix3.Scale(1, -1);
            //var scrToDcs = dcsToScr.Inverse();

            //从设备坐标转换到世界坐标系
            var wcsToDcs = Matrix3.Translate(center.X, center.Y) * Matrix3.Scale(scale);
            //var dcsToWcs = wcsToDcs.Inverse();

            //世界坐标系直接到屏幕
            this.WcsToScr = dcsToScr * wcsToDcs;
            this.ScrToWcs = this.WcsToScr.Inverse();
        }

        private SKPaint wallPen = new SKPaint { Color = SKColors.Gray, IsStroke = true };
        private SKPaint shapePen = new SKPaint { Color = SKColors.White, IsStroke = true };

        //https://learn.microsoft.com/zh-cn/xamarin/xamarin-forms/user-interface/graphics/skiasharp/curves/effects
        private void SkGL_PaintSurface(object? sender, SKPaintGLSurfaceEventArgs e)
        {
            CalFPS();
            var backRender = e.BackendRenderTarget;
            var canvas = e.Surface.Canvas;
            if (shapeCurves == null) return;

            canvas.Clear();
            DrawCurves(canvas, wallPen, this.wallCurves);
            DrawCurves(canvas, shapePen, this.shapeCurves);
        }

        private void DrawCurves(SKCanvas canvas, SKPaint pen, List<ICurve2d> curves)
        {
            foreach (var curve in curves)
            {
                switch (curve.Type)
                {
                    case Curve2dType.Line2d:
                        {
                            var line = curve as Line2d;
                            var start = WcsToScr.MultiplyPoint(line.Start);
                            var end = WcsToScr.MultiplyPoint(line.End);
                            canvas.DrawLine(start.ToSKPoint(), end.ToSKPoint(), pen);
                            break;
                        }
                    case Curve2dType.Arc2d:
                        {
                            var arc = curve as Arc2d;
                            var rect = new Box2d(arc.Center.X - arc.Radius, arc.Center.Y - arc.Radius, arc.Radius * 2, arc.Radius * 2);
                            var plt = WcsToScr.MultiplyPoint(rect.LeftTop);
                            var prb = WcsToScr.MultiplyPoint(rect.RightBottom);
                            var scrRect = new SKRect((float)plt.X, (float)plt.Y, (float)prb.X, (float)prb.Y);
                            var sweep = arc.EndAngle - arc.StartAngle;
                            //Skia绘制圆弧是按照顺时针的，与数学逻辑相反
                            canvas.DrawArc(scrRect, -(float)arc.EndAngle, (float)sweep, false, pen);
                            break;
                        }
                    case Curve2dType.Polyline2d:
                        {
                            var pline = curve as Polyline2d;
                            var scrPoints = pline.Points.Select((p) => WcsToScr.MultiplyPoint(p).ToSKPoint()).ToArray();
                            canvas.DrawPoints(SKPointMode.Polygon, scrPoints, pen);
                            break;
                        }
                    case Curve2dType.Polygon2d:
                        {
                            var polygon = curve as Polygon2d;
                            var scrPoints = polygon.Points.Select((p) => WcsToScr.MultiplyPoint(p).ToSKPoint()).ToList();
                            scrPoints.Add(scrPoints[0]);
                            canvas.DrawPoints(SKPointMode.Polygon, scrPoints.ToArray(), pen);
                            break;
                        }
                }
            }
        }

        #endregion

        #region UI Events

        private void SkGL_MouseClick(object? sender, MouseEventArgs e)
        {

        }

        private void LoadArchCategory()
        {
            cboCategory.Items.Clear();
            cboCategory.DisplayMember = "DisplayName";
            foreach (var item in ArchCategoryExt.ItemList)
            {
                cboCategory.Items.Add(item);
            }
            cboCategory.SelectedIndex = 2;//门
        }

      
        ArchCategoryItem categoryItem;
        private void cboCategory_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cboCategory.SelectedIndex == -1) return;

            cboSubCategory.Items.Clear();
            cboSubCategory.Text = "";
            lstShape.Items.Clear();
            cboSubCategory.DisplayMember = "DisplayName";
            cboSubCategory.ValueMember = "Name";
            categoryItem = cboCategory.SelectedItem as ArchCategoryItem;
            if (categoryItem.Value == ArchCategory.Door)
            {
                cboSubCategory.Items.AddRange(DoorCategoryExt.ItemList.ToArray());
                cboSubCategory.SelectedIndex = 0;
            }
            else if (categoryItem.Value == ArchCategory.Window)
            {
                cboSubCategory.Items.AddRange(WindowCategoryExt.ItemList.ToArray());
                cboSubCategory.SelectedIndex = 0;
            }
            else if (categoryItem.Value == ArchCategory.Stair)
            {
                cboSubCategory.Items.AddRange(StairCategoryExt.ItemList.ToArray());
                cboSubCategory.SelectedIndex = 0;
            }
        }

        private void cboSubCategory_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cboSubCategory.SelectedIndex == -1) return;

            lstShape.Items.Clear();
            lstShape.DisplayMember = "DisplayName";
            var subCategory = (cboSubCategory.SelectedItem as IEnumItem).Name;
            provider = Shape2dManager.LoadProvider(categoryItem.Name);
            var shapes=provider.Shapes.GetShapeList(subCategory);
            foreach (var item in shapes)
            {
                lstShape.Items.Add(item);
            }
        }

        private void SkGL_Resize(object? sender, EventArgs e)
        {
            ResetCoordMatrix();
        }
        private void QdArchShapeEditor_Shown(object? sender, EventArgs e)
        {
            // ResetCoordMatrix();
        }
        private void QdArchShapeEditor_Load(object sender, EventArgs e)
        {
            LcRuntime.RegistAssemblies.Add("QdArch");
            var action = new DoorAction();
            LoadArchCategory();
        }
        #endregion

        #region Private
        private void ShowDebug(string info)
        {
            txtDebug.AppendText(info + "\n");
        }
        /// <summary>
        /// 获取绘制背景墙体的曲线
        /// </summary>
        /// <param name="paramSet"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private List<ICurve2d> GetWallShape(LcParameterSet pset)
        {
            const double wlen = 500;
            var sc = new Shape2dCreator();
            var th = (double)pset["Thickness"];
            var w = (double)pset["Width"];

            var y = th / 2;
            var ptsLeft = new List<LightCAD.Core.Vector2>
            {
                new LightCAD.Core.Vector2(-wlen- w/2, y),
                new LightCAD.Core.Vector2(-w/2, y),
                new LightCAD.Core.Vector2(-w/2, -y),
                new LightCAD.Core.Vector2(-wlen- w/2, -y),
            };
            var plineLeft = new Polyline2d { Points = ptsLeft.ToArray() };
            sc.Curves.Add(plineLeft);

            var ptsRight = new List<LightCAD.Core.Vector2>
            {
                new LightCAD.Core.Vector2(wlen+ w/2, y),
                new LightCAD.Core.Vector2(w/2, y),
                new LightCAD.Core.Vector2(w/2, -y),
                new LightCAD.Core.Vector2(wlen+ w/2, -y),
            };
            var plineRight = new Polyline2d { Points = ptsRight.ToArray() };
            sc.Curves.Add(plineRight);

            return sc.Curves;
        }
        #endregion

      
    }
}